package com.dongnao.dnglide2.glide2;

import android.content.ComponentCallbacks;
import android.content.ComponentCallbacks2;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Configuration;
import android.net.Uri;
import android.support.v4.app.FragmentActivity;

import com.dongnao.dnglide2.glide2.cache.ArrayPool;
import com.dongnao.dnglide2.glide2.cache.MemoryCache;
import com.dongnao.dnglide2.glide2.cache.recycle.BitmapPool;
import com.dongnao.dnglide2.glide2.load.Engine;
import com.dongnao.dnglide2.glide2.load.codec.StreamBitmapDecoder;
import com.dongnao.dnglide2.glide2.load.model.FileLoader;
import com.dongnao.dnglide2.glide2.load.model.FileUriLoader;
import com.dongnao.dnglide2.glide2.load.model.HttpUriLoader;
import com.dongnao.dnglide2.glide2.load.model.StringModelLoader;

import java.io.File;
import java.io.InputStream;

/**
 * Created by Administrator on 2018/5/4.
 */

public class Glide implements ComponentCallbacks2 {

    private final MemoryCache memoryCache;
    private final BitmapPool bitmapPool;
    private final ArrayPool arrayPool;
    //
    private final RequestManagerRetriever requestManagerRetriever;

    private static Glide glide;


    private final Engine engine;
    private final GlideContext glideContext;

    protected Glide(Context context, GlideBuilder builder) {

        memoryCache = builder.memoryCache;
        bitmapPool = builder.bitmapPool;
        arrayPool = builder.arrayPool;
        //注册机
        Registry registry = new Registry();
        ContentResolver contentResolver = context.getContentResolver();
        registry.add(String.class, InputStream.class, new StringModelLoader.StreamFactory())
                .add(Uri.class, InputStream.class, new HttpUriLoader.Factory())
                .add(Uri.class, InputStream.class, new FileUriLoader.Factory(contentResolver))
                .add(File.class, InputStream.class, new FileLoader.Factory())
                .register(InputStream.class, new StreamBitmapDecoder(bitmapPool, arrayPool));

        engine = builder.engine;
        glideContext = new GlideContext(context, builder.defaultRequestOptions,
                engine, registry);

        requestManagerRetriever = new RequestManagerRetriever(glideContext);
    }

    /**
     * 默认实现
     *
     * @param context
     * @return
     */
    private static Glide get(Context context) {
        if (null == glide) {
            synchronized (Glide.class) {
                if (null == glide) {
                    init(context, new GlideBuilder());
                }
            }
        }
        return glide;
    }


    /**
     * 使用者可以定制自己的 GlideBuilder
     *
     * @param context
     * @param builder
     */
    public static void init(Context context, GlideBuilder builder) {
        if (Glide.glide != null) {
            tearDown();
        }
        Context applicationContext = context.getApplicationContext();
        Glide glide = builder.build(applicationContext);
        applicationContext.registerComponentCallbacks(glide);
        Glide.glide = glide;
    }

    public static synchronized void tearDown() {
        if (glide != null) {
            glide.glideContext
                    .getApplicationContext()
                    .unregisterComponentCallbacks(glide);
            glide.engine.shutdown();
        }
        glide = null;
    }

    public static RequestManager with(FragmentActivity activity) {
        return Glide.get(activity).requestManagerRetriever.get(activity);
    }


    /**
     * 当设备的信息改变的时候将会调用,某些时候你需要在系统一些配置信息改变的时候activity避免重新onCreate(),
     * 你就可以在android:configChanges声明，某个属性已经声明了，那么在这个属性的信息改变的时候就只会回调
     * onConfigurationChanged(Configuration newConfig)方法。
     * @param newConfig
     */
    @Override
    public void onConfigurationChanged(Configuration newConfig) {

    }

    /**
     * 内存紧张
     * 在系统内存不足，所有后台程序（优先级为background的进程，不是指后台运行的进程）都被杀死时，系统会调用OnLowMemory.
     *
     */
    @Override
    public void onLowMemory() {
        //memory和bitmappool顺序不能变
        //因为memory移除后会加入复用池
        memoryCache.clearMemory();
        bitmapPool.clearMemory();
        arrayPool.clearMemory();
    }

    /**
     * 需要释放内存
     * 系统会根据不同的内存状态来回调.他回调中的参数的意义：
     * 这三个是当前程序正在运行：
     * TRIM_MEMORY_RUNNING_MODERATE（5）：表示应用程序正常运行，但是目前手机的内存已经有点低了，
     * 您正在运行的进程可能需要在其他地方释放一些不必要的资源。系统可能会开始根据LRU缓存规则来去杀死进程了
     *
     *
     * TRIM_MEMORY_RUNNING_LOW(10)：表示应用程序正常运行，但是目前手机的内存已经有点低了，
     * 您正在运行的进程应该腾出不必要的资源，允许在其他地方使用的内存。
     *
     *
     * TRIM_MEMORY_RUNNING_CRITICAL(15)：表示应用程序正常运行，但在设备运行非常低内存，
     * 并即将不能够保持运行任何后台进程。您正在运行的进程应该腾出尽可能多的非关键资源，
     * 因为它可以允许在其他地方使用的内存。这种情况可以开始显着影响用户，在这之后就会调用onLowMemory（）
     * 报告已经没有保持的后台进程之后。
     *
     * 这三个是当前程序在后台：
     *
     * TRIM_MEMORY_UI_HIDDEN(20)：用户重新回到桌面调用
     *
     * TRIM_MEMORY_BACKGROUND(40)：表示手机目前内存已经很低了，系统准备开始根据LRU缓存来清理进程。
     * 这个时候我们的程序在LRU缓存列表的最近位置，是不太可能被清理掉的，
     * 但这时去释放掉一些比较容易恢复的资源能够让手机的内存变得比较充足，从而让我们的程序更长时间地保留在缓存当中，
     * 这样当用户返回我们的程序时会感觉非常顺畅，而不是经历了一次重新启动的过程。
     *
     * TRIM_MEMORY_MODERATE(60)：表示手机目前内存已经很低了，并且我们的程序处于LRU缓存列表的中间位置，
     * 如果手机内存还得不到进一步释放的话，那么我们的程序就有被系统杀掉的风险了。
     *
     * TRIM_MEMORY_COMPLETE(80)：表示手机目前内存已经很低了，并且我们的程序处于LRU缓存列表的最边缘位置，
     * 系统会最优先考虑杀掉我们的应用程序，在这个时候应当尽可能地把一切可以释放的东西都进行释放。
     *
     * @param level 内存状态
     */
    @Override
    public void onTrimMemory(int level) {
        memoryCache.trimMemory(level);
        bitmapPool.trimMemory(level);
        arrayPool.trimMemory(level);
    }


}
